[POOL-431] Improve replenishment strategy in GenericObjectPool.invalidateObject#454
Open
atakavci wants to merge 3 commits into
Open
[POOL-431] Improve replenishment strategy in GenericObjectPool.invalidateObject#454atakavci wants to merge 3 commits into
GenericObjectPool.invalidateObject#454atakavci wants to merge 3 commits into
Conversation
- switch to addIdleObect and check takeWaiters - synchronization to guard concurrent invalidations on same instance
garydgregory
requested changes
Apr 8, 2026
Member
There was a problem hiding this comment.
Hello @atakavci
Thank you for your pull request. You must add a unit test that fails without the changes to main applied. This is the only way we can avoid a future change from creating a regression.
TY!
Member
|
@psteitz |
Author
|
hey, hi @garydgregory , @psteitz , we 'd love to hear your feedback - happy to discuss or apply any necessary changes with the PR. thanks. |
|
@garydgregory @psteitz Any updates on this? |
ptaoussanis
added a commit
to taoensso/carmine
that referenced
this pull request
Jul 16, 2026
- Keep Commons Pool at v2.12.1 instead of v2.13.1, the latest version reported by `lein ancient`. - Commons Pool v2.13.0 intentionally changed `GenericObjectPool.invalidateObject` for POOL-424. It synchronously attempts to add a replacement after invalidation to fix a saturated-pool liveness race involving multiple waiting borrowers; v2.13.1 retains that behavior. https://issues.apache.org/jira/browse/POOL-424 - Carmine v3 and the v4 Cluster manager use `GenericKeyedObjectPool`, whose waiter-aware replacement behavior is unaffected. The ordinary v4 pooled manager, including Sentinel, uses `GenericObjectPool` and is directly affected. - With v2.13.1, ordinary v4 invalidation can create a Redis connection without waiting borrowers, mask the original application or I/O error when replacement creation fails, and leave a newly created idle connection after an active pre-clear connection is destroyed. The latter makes `_pooled-conn-manager-active-clear` observe one idle connection instead of zero, although the stale connection is correctly destroyed. - Track the open, Major POOL-431 regression and proposed waiter-aware, non-blocking correction in PR #454: https://issues.apache.org/jira/browse/POOL-431 apache/commons-pool#454 - Revisit the pin after POOL-431 is resolved. Before upgrading, verify saturated waiter liveness, no eager replacement without waiters, original error preservation, and pooled clear and Sentinel lifecycle behavior.
ptaoussanis
added a commit
to taoensso/carmine
that referenced
this pull request
Jul 16, 2026
- Keep Commons Pool at v2.12.1 instead of v2.13.1, the latest version reported by `lein ancient`. - Commons Pool v2.13.0 intentionally changed `GenericObjectPool.invalidateObject` for POOL-424. It synchronously attempts to add a replacement after invalidation to fix a saturated-pool liveness race involving multiple waiting borrowers; v2.13.1 retains that behavior. https://issues.apache.org/jira/browse/POOL-424 - Carmine v3 and the v4 Cluster manager use `GenericKeyedObjectPool`, whose waiter-aware replacement behavior is unaffected. The ordinary v4 pooled manager, including Sentinel, uses `GenericObjectPool` and is directly affected. - With v2.13.1, ordinary v4 invalidation can create a Redis connection without waiting borrowers, mask the original application or I/O error when replacement creation fails, and leave a newly created idle connection after an active pre-clear connection is destroyed. The latter makes `_pooled-conn-manager-active-clear` observe one idle connection instead of zero, although the stale connection is correctly destroyed. - Track the open, Major POOL-431 regression and proposed waiter-aware, non-blocking correction in PR #454: https://issues.apache.org/jira/browse/POOL-431 apache/commons-pool#454 - Revisit the pin after POOL-431 is resolved. Before upgrading, verify saturated waiter liveness, no eager replacement without waiters, original error preservation, and pooled clear and Sentinel lifecycle behavior.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A behavioral regression was introduced in commons-pool 2.13.0 as part of the fix for POOL-424, which ensures that
invalidateObject()replaces the destroyed instance by internally callingaddObject().This PR replaces the
addObject()replenishment call inGenericObjectPool.invalidateObjectwith astrategy consistent with how
GenericKeyedObjectPool.invalidateObjectalready handles thisvia
reuseCapacity().Rationale
addObject()brings potentially unexpected behaviour other than propogating factory fails to call site: it blocks up tomaxWait, silently no-ops whennumIdle >= maxIdle, creates unconditionally without checking for waiters, and propagates factory exceptions — which can causeinvalidateObject()to throw after theinvalidation has already succeeded.
The new approach is waiter-aware (
hasTakeWaiters), non-blocking (Duration.ZERO), bypassesthe
maxIdleinventory gate, and swallows factory exceptions viaswallowException. Poolstate is checked upfront with
!isClosed(); lifecycle management beyond that remains theresponsibility of
close().Files changed
src/main/java/org/apache/commons/pool2/impl/GenericObjectPool.javaThanks for your contribution to Apache Commons! Your help is appreciated!
Before you push a pull request, review this list:
mvn; that'smvnon the command line by itself.